//
//  YPopTipView.m
//  yuikemall
//
//  Created by yuike6 yuike6 on 12-2-15.
//  Copyright (c) 2012年 yuike. All rights reserved.
//

#import "YPopTipView.h"
//
//@interface YPopTipView (private)
//@property (nonatomic, retain, readwrite)	id	targetObject;
//@end
@implementation YPopTipView

@synthesize backgroundColor = backgroundColor_;
@synthesize delegate = delegate_;

@synthesize message = message_;
@synthesize customView = customView_;

@synthesize targetObject = targetObject_;
@synthesize textColor = textColor_;

@synthesize textFont = textFont_;
@synthesize textAlignment;

@synthesize animation = animation_;
@synthesize maxWidth;

@synthesize disableTapToDismiss;
@synthesize pointDirection = pointDirection_;

@synthesize targetPoint = targetPoint_;
@synthesize pointerSize = pointerSize_;

- (void) dealloc{
    YRelease(backgroundColor_);
    YRelease(message_);
    
    YRelease(textFont_);
    YRelease(textColor_);
    
    YRelease(customView_);
    YRelease(targetObject_);
    
    [super dealloc];
}
- (CGRect)bubbleFrame {
	CGRect bubbleFrame;
	if (self.pointDirection == PointDirectionUp) {
		bubbleFrame = CGRectMake(2.0, self.targetPoint.y + self.pointerSize, bubbleSize.width, bubbleSize.height);
	}
	else {
		bubbleFrame = CGRectMake(2.0, self.targetPoint.y - self.pointerSize-bubbleSize.height, bubbleSize.width, bubbleSize.height);
	}
	return bubbleFrame;
}

- (CGRect)contentFrame {
	CGRect bubbleFrame = [self bubbleFrame];
	CGRect contentFrame = CGRectMake(bubbleFrame.origin.x + cornerRadius,
									 bubbleFrame.origin.y + cornerRadius,
									 bubbleFrame.size.width - cornerRadius*2,
									 bubbleFrame.size.height - cornerRadius*2);
	return contentFrame;
}

- (void)layoutSubviews {
	if (self.customView) {
		
		CGRect contentFrame = [self contentFrame];
        [self.customView setFrame:contentFrame];
    }
}

- (void)drawRect:(CGRect)rect {
	    
	CGRect bubbleRect = [self bubbleFrame];
	
	CGContextRef c = UIGraphicsGetCurrentContext(); 
	
	CGContextSetRGBStrokeColor(c, 0.0, 0.0, 0.0, 1.0);	// black
	CGContextSetLineWidth(c, 1.0);
    
	CGMutablePathRef bubblePath = CGPathCreateMutable();
	
	if (self.pointDirection == PointDirectionUp) {
		CGPathMoveToPoint(bubblePath, NULL, self.targetPoint.x, self.targetPoint.y);
		CGPathAddLineToPoint(bubblePath, NULL, self.targetPoint.x + self.pointerSize, self.targetPoint.y + self.pointerSize);
		
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y+cornerRadius,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y+bubbleRect.size.height,
							bubbleRect.origin.x+bubbleRect.size.width-cornerRadius, bubbleRect.origin.y+bubbleRect.size.height,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x, bubbleRect.origin.y+bubbleRect.size.height,
							bubbleRect.origin.x, bubbleRect.origin.y+bubbleRect.size.height-cornerRadius,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x, bubbleRect.origin.y,
							bubbleRect.origin.x+cornerRadius, bubbleRect.origin.y,
							cornerRadius);
		CGPathAddLineToPoint(bubblePath, NULL, self.targetPoint.x - self.pointerSize, self.targetPoint.y + self.pointerSize);
	}
	else {
		CGPathMoveToPoint(bubblePath, 
                          NULL, 
                          self.targetPoint.x, 
                          self.targetPoint.y);
		CGPathAddLineToPoint(bubblePath, NULL, self.targetPoint.x - self.pointerSize, self.targetPoint.y - self.pointerSize);
		
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x, bubbleRect.origin.y+bubbleRect.size.height,
							bubbleRect.origin.x, bubbleRect.origin.y+bubbleRect.size.height-cornerRadius,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x, bubbleRect.origin.y,
							bubbleRect.origin.x+cornerRadius, bubbleRect.origin.y,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y+cornerRadius,
							cornerRadius);
		CGPathAddArcToPoint(bubblePath, NULL,
							bubbleRect.origin.x+bubbleRect.size.width, bubbleRect.origin.y+bubbleRect.size.height,
							bubbleRect.origin.x+bubbleRect.size.width-cornerRadius, bubbleRect.origin.y+bubbleRect.size.height,
							cornerRadius);
		CGPathAddLineToPoint(bubblePath, NULL, self.targetPoint.x + self.pointerSize, self.targetPoint.y - self.pointerSize);
	}
   

	CGPathCloseSubpath(bubblePath);
   
	
	// Draw shadow 
    /*
        不知道为什么，这部分代码在new pad 上运行比较慢，语句为:CGContextFillPath(c);
        ipad2上运行没有问题， 先不运行这部分代码，日后有再找原因吧
        note:
        Quartz 2D (Core Graphics) graphics are not accelerated on the iPhone. Path fills are likely CPU bound as well. If you want hardware acceleration, you'll have to convert your scene to OpenGL ES (triangle strips and textures).
        http://stackoverflow.com/questions/4091235/how-to-accelerate-quartz-2d
         
	CGContextAddPath(c, bubblePath);
    CGContextSaveGState(c);
	CGContextSetShadow(c, CGSizeMake(0, 3), 5);
	CGContextSetRGBFillColor(c, 0.0, 0.0, 0.0, 0.9);
	CGContextFillPath(c); // slow in new pad
    CGContextRestoreGState(c);
     */
	
    
	// Draw clipped background gradient
	CGContextAddPath(c, bubblePath);
	CGContextClip(c);
 
	CGFloat bubbleMiddle = (bubbleRect.origin.y+(bubbleRect.size.height/2)) / self.bounds.size.height;
    	
	CGGradientRef myGradient;
	CGColorSpaceRef myColorSpace;
	size_t locationCount = 5;
	CGFloat locationList[] = {0.0, bubbleMiddle-0.03, bubbleMiddle, bubbleMiddle+0.03, 1.0};
    
	CGFloat colourHL = 0.0;
	if (highlight) {
		colourHL = 0.25;
	}
	CGFloat red;
	CGFloat green;
	CGFloat blue;
	CGFloat alpha;
	int numComponents = CGColorGetNumberOfComponents([self.backgroundColor CGColor]);
	const CGFloat *components = CGColorGetComponents([self.backgroundColor CGColor]);
	if (numComponents == 2) {
		red = components[0];
		green = components[0];
		blue = components[0];
		alpha = components[1];
	}
	else {
		red = components[0];
		green = components[1];
		blue = components[2];
		alpha = components[3];
	}
    
     /* -----------------  start  ---------------------------*/
    /* 这个就是上下分隔效果的代码
	CGFloat colorList[] = {
		//red, green, blue, alpha 
		red*1.16+colourHL, green*1.16+colourHL, blue*1.16+colourHL, alpha,
		red*1.16+colourHL, green*1.16+colourHL, blue*1.16+colourHL, alpha,
		red*1.08+colourHL, green*1.08+colourHL, blue*1.08+colourHL, alpha,
		red     +colourHL, green     +colourHL, blue     +colourHL, alpha,
		red     +colourHL, green     +colourHL, blue     +colourHL, alpha
	};*/
    
    
    CGFloat colorList[] = {
		//red, green, blue, alpha 
		red+colourHL, green+colourHL, blue+colourHL, alpha,
		red+colourHL, green+colourHL, blue+colourHL, alpha,
		red+colourHL, green+colourHL, blue+colourHL, alpha,
		red     +colourHL, green     +colourHL, blue     +colourHL, alpha,
		red     +colourHL, green     +colourHL, blue     +colourHL, alpha
	};
    
    /* -----------------  end  ---------------------------*/
    
    
	myColorSpace = CGColorSpaceCreateDeviceRGB();
	myGradient = CGGradientCreateWithColorComponents(myColorSpace, colorList, locationList, locationCount);
	CGPoint startPoint, endPoint;
	startPoint.x = 0;
	startPoint.y = 0;
	endPoint.x = 0;
	endPoint.y = CGRectGetMaxY(self.bounds);
	 
	CGContextDrawLinearGradient(c, myGradient, startPoint, endPoint,0);
	CGGradientRelease(myGradient);
	CGColorSpaceRelease(myColorSpace);
	
	CGContextSetRGBStrokeColor(c, 0.4, 0.4, 0.4, 1.0);     
	CGContextAddPath(c, bubblePath);   
    // 可以产生黑色的边框
//	CGContextDrawPath(c, kCGPathStroke);

	CGPathRelease(bubblePath);
	
	// Draw text
	if (self.message) {
		[self.textColor set];
		CGRect textFrame = [self contentFrame];
        [self.message drawInRect:textFrame
                        withFont:self.textFont
                   lineBreakMode:UILineBreakModeWordWrap
                       alignment:UITextAlignmentCenter];
    }    
}

- (void)presentPointingAtPoint:(CGPoint )point inView:(UIView *)containerView animated:(BOOL)animated
{
    [containerView addSubview:self];
    
    CGFloat rectWidth;
    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // iPad
        if (maxWidth) {
            if (maxWidth < containerView.frame.size.width) {
                rectWidth = maxWidth;
            }
            else {
                rectWidth = containerView.frame.size.width - 20;
            }
        }
        else {
            rectWidth = (int)(containerView.frame.size.width/3);
        }
    }
    else {
        // iPhone
        if (maxWidth) {
            if (maxWidth < containerView.frame.size.width) {
                rectWidth = maxWidth;
            }
            else {
                rectWidth = containerView.frame.size.width - 10;
            }
        }
        else {
            rectWidth = (int)(containerView.frame.size.width*2/3);
        }
    }
    
	CGSize textSize = CGSizeZero;
    
    if (self.message!=nil) {
        textSize= [self.message sizeWithFont:self.textFont
                           constrainedToSize:CGSizeMake(rectWidth, 99999.0)
                               lineBreakMode:UILineBreakModeWordWrap];
    }
    if (self.customView != nil) {
        textSize = self.customView.frame.size;
    }
    
	bubbleSize = CGSizeMake(textSize.width + cornerRadius*2, textSize.height + cornerRadius*2);
	
	CGPoint targetRelativeOrigin    = point;
    
	CGPoint containerRelativeOrigin = [containerView.superview convertPoint:containerView.frame.origin toView:containerView.superview];
    
	CGFloat pointerY;	// Y coordinate of pointer target (within containerView)
	
	if (targetRelativeOrigin.y+ point.y < containerRelativeOrigin.y) {
		pointerY = 0.0;
		self.pointDirection = PointDirectionUp;
	}
	else if (targetRelativeOrigin.y > containerRelativeOrigin.y+containerView.bounds.size.height) {
		pointerY = containerView.bounds.size.height;
		self.pointDirection = PointDirectionDown;
	}
	else {
		CGPoint targetOriginInContainer = point;
		CGFloat sizeBelow = containerView.bounds.size.height - targetOriginInContainer.y;
		if (sizeBelow > targetOriginInContainer.y) {
			pointerY = targetOriginInContainer.y + point.y;
			self.pointDirection = PointDirectionUp;
		}
		else {
			pointerY = targetOriginInContainer.y;
			self.pointDirection = PointDirectionDown;
		}
	}
	
	CGFloat W = containerView.frame.size.width;
	
	CGPoint p = point;
	CGFloat x_p = p.x;
	CGFloat x_b = x_p - roundf(bubbleSize.width/2);
	if (x_b < sidePadding) {
		x_b = sidePadding;
	}
	if (x_b + bubbleSize.width + sidePadding > W) {
		x_b = W - bubbleSize.width - sidePadding;
	}
	if (x_p - self.pointerSize < x_b + cornerRadius) {
		x_p = x_b + cornerRadius + self.pointerSize;
	}
	if (x_p + self.pointerSize > x_b + bubbleSize.width - cornerRadius) {
		x_p = x_b + bubbleSize.width - cornerRadius - self.pointerSize;
	}
	
	CGFloat fullHeight = bubbleSize.height + self.pointerSize + 10.0;
	CGFloat y_b;
	if (self.pointDirection == PointDirectionUp) {
		y_b = topMargin + pointerY;
		self.targetPoint = CGPointMake(x_p-x_b, 0);
	}
	else {
		y_b = pointerY - fullHeight;
		self.targetPoint = CGPointMake(x_p-x_b, fullHeight-2.0);
	}
	
	CGRect finalFrame = CGRectMake(x_b-sidePadding,
								   y_b,
								   bubbleSize.width+sidePadding*2,
								   fullHeight);
    
   	
	if (animated) {
        if (self.animation == YPopTipAnimationSlide) {
            self.alpha = 0.0;
            CGRect startFrame = finalFrame;
            startFrame.origin.y += 10;
            self.frame = startFrame;
        }
		else if (self.animation == YPopTipAnimationPop) {
            self.frame = finalFrame;
            self.alpha = 0.5;
            
            // start a little smaller
            self.transform = CGAffineTransformMakeScale(0.75f, 0.75f);
            
            // animate to a bigger size
            [UIView beginAnimations:nil context:nil];
            [UIView setAnimationDelegate:self];
            [UIView setAnimationDidStopSelector:@selector(popAnimationDidStop:finished:context:)];
            [UIView setAnimationDuration:0.15f];
            self.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
            self.alpha = 1.0;
            [UIView commitAnimations];
        }
		
		[self setNeedsDisplay];
		
		if (self.animation == YPopTipAnimationSlide) {
			[UIView beginAnimations:nil context:nil];
			self.alpha = 1.0;
			self.frame = finalFrame;
			[UIView commitAnimations];
		}
	}
	else {
		// Not animated
		[self setNeedsDisplay];
		self.frame = finalFrame;
	}

}

- (void)presentPointingAtView:(UIView *)targetView inView:(UIView *)containerView animated:(BOOL)animated {
	if (!self.targetObject) {
		self.targetObject = targetView;
	}
	
	[containerView addSubview:self];
    
	// Size of rounded rect
	CGFloat rectWidth;
    
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // iPad
        if (maxWidth) {
            if (maxWidth < containerView.frame.size.width) {
                rectWidth = maxWidth;
            }
            else {
                rectWidth = containerView.frame.size.width - 20;
            }
        }
        else {
            rectWidth = (int)(containerView.frame.size.width/3);
        }
    }
    else {
        // iPhone
        if (maxWidth) {
            if (maxWidth < containerView.frame.size.width) {
                rectWidth = maxWidth;
            }
            else {
                rectWidth = containerView.frame.size.width - 10;
            }
        }
        else {
            rectWidth = (int)(containerView.frame.size.width*2/3);
        }
    }
    
	CGSize textSize = CGSizeZero;
    
    if (self.message!=nil) {
        textSize= [self.message sizeWithFont:self.textFont
                           constrainedToSize:CGSizeMake(rectWidth, 99999.0)
                               lineBreakMode:UILineBreakModeWordWrap];
    }
    if (self.customView != nil) {
        textSize = self.customView.frame.size;
    }
    
	bubbleSize = CGSizeMake(textSize.width + cornerRadius*2, textSize.height + cornerRadius*2);
	
	CGPoint targetRelativeOrigin    = [targetView.superview convertPoint:targetView.frame.origin toView:containerView.superview];
	CGPoint containerRelativeOrigin = [containerView.superview convertPoint:containerView.frame.origin toView:containerView.superview];
    
	CGFloat pointerY;	// Y coordinate of pointer target (within containerView)
	
	if (targetRelativeOrigin.y+targetView.bounds.size.height < containerRelativeOrigin.y) {
		pointerY = 0.0;
		self.pointDirection = PointDirectionUp;
	}
	else if (targetRelativeOrigin.y > containerRelativeOrigin.y+containerView.bounds.size.height) {
		pointerY = containerView.bounds.size.height;
		self.pointDirection = PointDirectionDown;
	}
	else {
		CGPoint targetOriginInContainer = [targetView convertPoint:CGPointMake(0.0, 0.0) toView:containerView];
		CGFloat sizeBelow = containerView.bounds.size.height - targetOriginInContainer.y;
		if (sizeBelow > targetOriginInContainer.y) {
			pointerY = targetOriginInContainer.y + targetView.bounds.size.height;
			self.pointDirection = PointDirectionUp;
		}
		else {
			pointerY = targetOriginInContainer.y;
			self.pointDirection = PointDirectionDown;
		}
	}
	
	CGFloat W = containerView.frame.size.width;
	
	CGPoint p = [targetView.superview convertPoint:targetView.center toView:containerView];
	CGFloat x_p = p.x;
	CGFloat x_b = x_p - roundf(bubbleSize.width/2);
	if (x_b < sidePadding) {
		x_b = sidePadding;
	}
	if (x_b + bubbleSize.width + sidePadding > W) {
		x_b = W - bubbleSize.width - sidePadding;
	}
	if (x_p - self.pointerSize < x_b + cornerRadius) {
		x_p = x_b + cornerRadius + self.pointerSize;
	}
	if (x_p + self.pointerSize > x_b + bubbleSize.width - cornerRadius) {
		x_p = x_b + bubbleSize.width - cornerRadius - self.pointerSize;
	}
	
	CGFloat fullHeight = bubbleSize.height + self.pointerSize + 10.0;
	CGFloat y_b;
	if (self.pointDirection == PointDirectionUp) {
		y_b = topMargin + pointerY;
		self.targetPoint = CGPointMake(x_p-x_b, 0);
	}
	else {
		y_b = pointerY - fullHeight;
		self.targetPoint = CGPointMake(x_p-x_b, fullHeight-2.0);
	}
	
	CGRect finalFrame = CGRectMake(x_b-sidePadding,
								   y_b,
								   bubbleSize.width+sidePadding*2,
								   fullHeight);
    
   	
	if (animated) {
        if (self.animation == YPopTipAnimationSlide) {
            self.alpha = 0.0;
            CGRect startFrame = finalFrame;
            startFrame.origin.y += 10;
            self.frame = startFrame;
        }
		else if (self.animation == YPopTipAnimationPop) {
            self.frame = finalFrame;
            self.alpha = 0.5;
            
            // start a little smaller
            self.transform = CGAffineTransformMakeScale(0.75f, 0.75f);
            
            // animate to a bigger size
            [UIView beginAnimations:nil context:nil];
            [UIView setAnimationDelegate:self];
            [UIView setAnimationDidStopSelector:@selector(popAnimationDidStop:finished:context:)];
            [UIView setAnimationDuration:0.15f];
            self.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
            self.alpha = 1.0;
            [UIView commitAnimations];
        }
		
		[self setNeedsDisplay];
		
		if (self.animation == YPopTipAnimationSlide) {
			[UIView beginAnimations:nil context:nil];
			self.alpha = 1.0;
			self.frame = finalFrame;
			[UIView commitAnimations];
		}
	}
	else {
		// Not animated
		[self setNeedsDisplay];
		self.frame = finalFrame;
	}
}

- (void)presentPointingAtBarButtonItem:(UIBarButtonItem *)barButtonItem animated:(BOOL)animated {
	UIView *targetView = (UIView *)[barButtonItem performSelector:@selector(view)];
	UIView *targetSuperview = [targetView superview];
	UIView *containerView = nil;
	if ([targetSuperview isKindOfClass:[UINavigationBar class]]) {
		UINavigationController *navController = [(UINavigationBar *)targetSuperview delegate];
		containerView = [[navController topViewController] view];
	}
	else if ([targetSuperview isKindOfClass:[UIToolbar class]]) {
		containerView = [targetSuperview superview];
	}
	
	if (nil == containerView) {
		DebugLog(@"Cannot determine container view from UIBarButtonItem: %@", barButtonItem);
		self.targetObject = nil;
		return;
	}
	
	self.targetObject = barButtonItem;
	
	[self presentPointingAtView:targetView inView:containerView animated:animated];
}

- (void)finaliseDismiss {
	[self removeFromSuperview];
	highlight = NO;
	self.targetObject = nil;
}

- (void)dismissAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
	[self finaliseDismiss];
}

- (void)dismissAnimated:(BOOL)animated {
	
	if (animated) {
		CGRect frame = self.frame;
		frame.origin.y += 10.0;
		
		[UIView beginAnimations:nil context:nil];
		self.alpha = 0.0;
		self.frame = frame;
		[UIView setAnimationDelegate:self];
		[UIView setAnimationDidStopSelector:@selector(dismissAnimationDidStop:finished:context:)];
		[UIView commitAnimations];
	}
	else {
		[self finaliseDismiss];
	}
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	if (self.disableTapToDismiss) {
		[super touchesBegan:touches withEvent:event];
		return;
	}
	
	highlight = YES;
	[self setNeedsDisplay];
	
	[self dismissAnimated:YES];
	
	if (self.delegate && [self.delegate respondsToSelector:@selector(popTipViewWasDismissedByUser:)]) {
		[self.delegate popTipViewWasDismissedByUser:self];
	}
}

- (void)popAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    // at the end set to normal size
	[UIView beginAnimations:nil context:nil];
	[UIView setAnimationDuration:0.1f];
	self.transform = CGAffineTransformIdentity;
	[UIView commitAnimations];
}

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
		self.opaque = NO;
		
		cornerRadius = 10.0;
		topMargin = 2.0;
		self.pointerSize = 12.0;
		sidePadding = 2.0;
		
		self.textFont = [UIFont boldSystemFontOfSize:14.0];
		self.textColor = [UIColor whiteColor];
		self.textAlignment = UITextAlignmentCenter;
		self.backgroundColor = [UIColor colorWithRed:62.0/255.0 green:60.0/255.0 blue:154.0/255.0 alpha:1.0];
        self.animation = YPopTipAnimationSlide;
    }
    return self;
}

- (PointDirection) getPointDirection {
    return self.pointDirection;
}

- (id)initWithMessage:(NSString *)messageToShow {
	CGRect frame = CGRectZero;
	
	if ((self = [self initWithFrame:frame])) {
		self.message = messageToShow;
	}
	return self;
}

- (id)initWithCustomView:(UIView *)aView {
	CGRect frame = CGRectZero;
	
	if ((self = [self initWithFrame:frame])) {
		self.customView = aView;
        [self addSubview:self.customView];
	}
	return self;
}


@end
